#include "reactor.h"
#include "acceptor.h"
#include "event.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include "common.h"
#include "jobqueue.h"

reactor_t *create_reactor(int epollfd, thpool_t *thpool)
{
	reactor_t *reactor;

	reactor = (reactor_t *)malloc(sizeof(reactor_t));
	if (reactor == NULL)
	{
		outputError(errno, "%s", "malloc reactor");
	}

	reactor->add_eh = add_event_handle;
	reactor->rm_eh = rm_event_handle;
	reactor->event_loop = event_loop;
	reactor->thpool = thpool;
	reactor->acceptor = NULL;

	reactor->core = (reactor_core_t *)malloc(sizeof(reactor_core_t));
	if (reactor->core == NULL)
	{
		outputError(errno, "%s", "malloc reactor_core");
	}

	reactor->core->epoll_fd = epollfd;
	reactor->core->eh_list = (event_handler_list_t *)malloc(sizeof(event_handler_list_t));
	if (reactor->core->eh_list == NULL)
	{
		outputError(errno, "%s", "malloc event_handler_list_t");
	}

	reactor->core->eh_list->current_len = 0;
	reactor->core->eh_list->head = reactor->core->eh_list->tail = NULL;

	return reactor;
}

int add_event_handle(struct reactor *self, event_handler_t *eh)
{
	struct epoll_event ev;
	event_handler_node_t *node;

	if (self->core->eh_list->current_len >= MAX_USERS)
	{
		outputError(errno, "%s%d", "limit ", MAX_USERS);
	}
	else
	{
		node = (event_handler_node_t *)malloc(sizeof(event_handler_node_t));
		if (node == NULL)
		{
			outputError(errno, "%s", "malloc event_handler_node_t");
		}
		node->eh = eh;
		node->next = NULL;
		if (self->core->eh_list->current_len == 0)
		{
			self->core->eh_list->head = self->core->eh_list->tail = node;
		}
		else
		{
			self->core->eh_list->tail->next = node;
			self->core->eh_list->tail = node;
		}
		self->core->eh_list->current_len++;
	}

	ev.data.fd = eh->fd;
	ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
	// ev.events = EPOLLIN;

	if (epoll_ctl(self->core->epoll_fd, EPOLL_CTL_ADD, eh->fd, &ev) != 0)
	{
		outputError(errno, "%s", "epoll_ctl");
	}

	return 0;
}

int rm_event_handle(struct reactor *self, int fd)
{
	int i;
	event_handler_node_t *node, *prev;

	for (i = 1, node = self->core->eh_list->head, prev = NULL; i <= self->core->eh_list->current_len; i++, prev = node, node = node->next)
	{
		if (node->eh->fd == fd)
		{
			break;
		}
	}

	if (i > self->core->eh_list->current_len)
	{
		outputError(errno, "%s", "could not find eh");
	}

	if (--self->core->eh_list->current_len == 0)
	{
		self->core->eh_list->head = self->core->eh_list->tail = NULL;
	}
	else
	{
		prev->next = node->next;
		self->core->eh_list->tail = prev;
	}

	free(node->eh);
	free(node);

	if (epoll_ctl(self->core->epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1)
	{
		outputError(errno, "%s", "epoll_ctl");
	}
}

int event_loop(struct reactor *self)
{
	struct epoll_event evlist[MAX_USERS];
	int readyN, i;
	event_handler_t *eh;
	handle_event_msg_t arg;

	while (1)
	{
		if ((readyN = epoll_wait(self->core->epoll_fd, evlist, MAX_USERS, -1)) == -1)
		{
			if (errno == EINTR)
			{
				continue;
			}
			else
			{
				outputError(errno, "%s", "epoll_wait");
			}
		}

		printf("readyn = %d\n", readyN);

		for (i = 0; i < readyN; i++)
		{

			if (evlist[i].events & EPOLLIN)
			{
				if (evlist[i].data.fd == self->acceptor->listenfd)
				{
					self->acceptor->handle_event(self);
				}
				else
				{
					eh = find_eh(self, evlist[i].data.fd);
					arg.eh = eh;
					arg.events = evlist[i].events;
					arg.fd = evlist[i].data.fd;

					insert_jobqueue(self->thpool, eh, arg);
				}
			}

			if (evlist[i].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP))
			{
				rm_event_handle(self, evlist[i].data.fd);
				printf("user down and eh num %d\n", self->core->eh_list->current_len);
			}
		}
	}
}

event_handler_t *find_eh(struct reactor *self, int fd)
{
	int i;
	event_handler_node_t *node;

	for (i = 1, node = self->core->eh_list->head; i <= self->core->eh_list->current_len; i++, node = node->next)
	{
		if (node->eh->fd == fd)
		{
			break;
		}
	}

	if (i > self->core->eh_list->current_len)
	{
		outputError(errno, "%s", "could not find eh");
	}

	return node->eh;
}
